﻿import flash.display.BitmapData;
import flash.geom.ColorTransform;
import flash.geom.Rectangle;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.filters.BlurFilter;
import mx.utils.Delegate;

import kliment.geom.BoundsRectangle;
import kliment.geom.draw.Draw;
import kliment.geom.draw.DrawStyle;
import kliment.geom.draw.GradientStyle;
import kliment.display.MCC;
import kliment.geom.Geom;

/**
 * Drop reflection under target moviclip 
 * 
 * @author	Kliment
 * @version	1.4.12
 */

class kliment.effect.Reflection {
	private var _target_mc:MovieClip;
	private var _distance:Number = 0;
	private var _ratio:Number = 1;
	private var _reflectionColors:Array = [0x000000, 0x000000];
	private var _reflectionAlphas:Array = [0, 100];
	private var _reflectionRatios:Array = [0, 255];
	private var _lifeUpdate:Boolean = false;
	private var _targetBounds:BoundsRectangle;
	private var _blurFilter:BlurFilter
	
	private var _reflection_mc:MovieClip;
	private var _body_mc:MovieClip;
	private var _bodyBMP:BitmapData;
	private var _reflectionBMP:BitmapData;
	private var _maskBMP:BitmapData;
	private var _drawRectangle:Rectangle;
	private var _aMatrix:Matrix;
	private var _aDrawStyle:DrawStyle;
	private var _aColorTransform:ColorTransform;
	private var _aBlendMode:String = 'normal';
	private var _colorDraw:Number = 0x000000;
	private var _alphaDraw:Boolean = true;
	private var _pixelSnapping:String = 'auto';
	private var _pointDraw:Point;
	private var _clipRect:Rectangle;
	
	public var smoothing:Boolean = true;
	
	private var _x:Number;
	private var _y:Number;
	
	public function Reflection(target_mc:MovieClip, lifeUpdate:Boolean, clipRect:Rectangle) {
		_target_mc = target_mc;
		distance = _distance;
		_clipRect = clipRect;
		_init();
		this.lifeUpdate = lifeUpdate;
	}
	
	private function _init():Void {
		_aColorTransform = new ColorTransform();
		_pointDraw = new Point();
		_aDrawStyle = new DrawStyle(null, null, new GradientStyle(GradientStyle.TYPE_LINEAR, _reflectionColors, _reflectionAlphas, _reflectionRatios));
		_reflection_mc = MCC.create(_target_mc._parent);
		_body_mc = MCC.create(_reflection_mc);
		_reflection_mc.swapDepths(_target_mc.getDepth() - 1);
		_config();
	}
	
	private function _config():Void {
		_drawRectangle = MCC.toBounds(_target_mc.getBounds()).toRectangle();
		_drawRectangle.width = Math.round(_drawRectangle.width);
		_drawRectangle.height = Math.round(_drawRectangle.height);
		_clipRect = _clipRect || _drawRectangle.clone();//new Rectangle( _drawRectangle.x, _drawRectangle.y, _drawRectangle.width - _drawRectangle.x, _drawRectangle.height - _drawRectangle.y);
		_aMatrix = new Matrix(1, 0, 0, 1, -_clipRect.x, -_clipRect.y);
		var createMatrix:Matrix = new Matrix();
		createMatrix.createGradientBox(_clipRect.width, _clipRect.height, Geom.halfPi, 0, 0);
		var mask_mc:MovieClip = MCC.create(_target_mc._parent);
		_aDrawStyle.fillGradientStyle.colors = _reflectionColors;
		_aDrawStyle.fillGradientStyle.alphas = _reflectionAlphas;
		_aDrawStyle.fillGradientStyle.ratios = _reflectionRatios;
		_aDrawStyle.fillGradientStyle.ratios = _reflectionRatios;
		_aDrawStyle.fillGradientStyle.matrix = createMatrix;
		Draw.rectangle(mask_mc, new Rectangle(0, 0, _clipRect.width, _clipRect.height), _aDrawStyle);
		_maskBMP.dispose();
		_maskBMP = new BitmapData(mask_mc._width, mask_mc._height, true, _colorDraw);
		_maskBMP.draw(mask_mc);
		MCC.remove(mask_mc);
		
		_body_mc._yscale = -100;
		_body_mc._y = _clipRect.height;
		
		_bodyBMP.dispose();
		_bodyBMP = new BitmapData(_clipRect.width, _clipRect.height, _alphaDraw, _colorDraw);
		_reflectionBMP.dispose();
		_reflectionBMP = new BitmapData(_clipRect.width, _clipRect.height, _alphaDraw, _colorDraw);
		MCC.attachBitmap(_body_mc, _reflectionBMP, _pixelSnapping, smoothing);
		_render();
	}
	
	private function _render():Void {
		_bodyBMP.fillRect(_bodyBMP.rectangle, _colorDraw);
		_bodyBMP.draw(_target_mc, _aMatrix, _aColorTransform, _aBlendMode);
		_reflectionBMP.fillRect(_bodyBMP.rectangle, _colorDraw);
		_reflectionBMP.copyPixels(_bodyBMP, _bodyBMP.rectangle, _pointDraw, _maskBMP, _pointDraw, _alphaDraw);
		_setPosition();
	}
	
	private function _setPosition():Void {
		if (isNaN(_x) || isNaN(_y))
			_targetBounds = MCC.getBounds(_target_mc);
		_reflection_mc._yscale = _target_mc._yscale * _ratio;
		_reflection_mc._xscale = _target_mc._xscale;
		_reflection_mc._x = isFinite(_x)?_x:_targetBounds.xMin;
		_reflection_mc._y = (isFinite(_y)?_y:_targetBounds.yMax) + _distance;
	}
	
	public function update():Void {
		_render();
	}
	
	public function get lifeUpdate():Boolean { return _lifeUpdate; }
	public function set lifeUpdate(value:Boolean):Void 	{
		if (_lifeUpdate == value) return;
		if (value) 
			_reflection_mc.onEnterFrame = Delegate.create(this,_render);
		else 
			_reflection_mc.onEnterFrame = null;
		_lifeUpdate = value;
	}
	
	public function get distance():Number { return _distance; }
	public function set distance(value:Number):Void {
		_distance = value;
		_setPosition();
	}	
	
	public function get ratio():Number { return _ratio; }
	public function set ratio(value:Number):Void 	{
		_ratio = value;
		_setPosition();
	}
	
	public function get reflectionAlphas():Array { return _reflectionAlphas; }
	public function set reflectionAlphas(value:Array):Void {
		_reflectionAlphas = value;
		_config();
		_render();
	}
	
	public function get reflectionRatios():Array { return _reflectionRatios; }
	public function set reflectionRatios(value:Array):Void {
		_reflectionRatios = value;
		_config();
		_render();
	}
	
	public function get blurFilter():BlurFilter { return _blurFilter; }
	public function set blurFilter(value:BlurFilter):Void {
		_blurFilter = value;
		if (value) 
			_reflection_mc.filters = [value];
		else 
			_reflection_mc.filters = [];
	}
	
	public function get x():Number { return _x; }
	public function set x(value:Number):Void {
		_x = value;
		_setPosition();
	}
	
	public function get y():Number { return _y; }
	public function set y(value:Number):Void {
		_y = value;
		_setPosition();
	}
	
	public function get clipRect():Rectangle { return _clipRect; }
	public function set clipRect(value:Rectangle):Void {
		_clipRect = value;
		_config();
	}
	
	public function remove():Void {
		_bodyBMP.dispose();
		_reflectionBMP.dispose();
		lifeUpdate = false;
		MCC.remove(_reflection_mc);
		delete this;
	}
}